package com.gugee.ins.data.blogger.statistics.core;


import com.gugee.ins.common.constant.InsBloggerMsgTypeCodeEnum;
import com.gugee.ins.common.dal.service.blogger.InsRelBloggerActiveFollowerDao;
import com.gugee.ins.common.dal.service.dic.InsDicGenerationDao;
import com.gugee.ins.common.dal.service.statistics.InsStBloggerRealFollowingDao;
import com.gugee.ins.common.dal.service.statistics.*;
import com.gugee.ins.common.model.mysql.blogger.InsBloggerMain;
import com.gugee.ins.common.model.mysql.dic.InsDicGeneration;
import com.gugee.ins.common.model.mysql.statistics.InsStBloggerGeneration;
import com.gugee.ins.common.model.mysql.statistics.*;
import com.gugee.ins.data.common.msg.InsBloggerMessage;
import com.xiguaji.boot.toolkit.ThreadPoolUtils;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@Slf4j
public class StBloggerActiveFollowerDataService extends StBaseService{


    private static final String THREAD_POOL_NAME = "BloggerActiveRealFollower-Thread";

    @Autowired
    @Qualifier("insBloggerMsgBaseInfoProducer")
    private KafkaTemplate<Long, InsBloggerMessage> insBloggerMsgBaseInfoProducer;

    @Autowired
    private InsRelBloggerActiveFollowerDao insRelBloggerActiveFollowerDao;

    @Autowired
    private InsStBloggerGenerationDao insStBloggerGenerationDao;
    @Autowired
    private InsStBloggerLanguageDao insStBloggerLanguageDao;
    @Autowired
    private InsStBloggerNationDao insStBloggerNationDao;
    @Autowired
    private InsStBloggerRaceDao insStBloggerRaceDao;
    @Autowired
    private InsStBloggerRealFollowingDao insStBloggerRealFollowingDao;
    @Autowired
    private InsStBloggerFlBrandDao insStBloggerFlBrandDao;
    @Autowired
    private InsStBloggerFlBrandCategoryDao insStBloggerFlBrandCategoryDao;
    @Autowired
    private InsDicGenerationDao insDicGenerationDao;

    /**
     * insStBloggerIncomeDao
     */
    @Autowired
    private InsStBloggerIncomeDao insStBloggerIncomeDao;

    private List<InsDicGeneration> dicGenerations;

    private InsDicGeneration adult;

    @PostConstruct
    public void init() {
        forkJoinPool = ThreadPoolUtils.forkJoinPool(bloggerStatisticsAppConfig.getBloggerActiveFollowerDataThreadPoolSize(), THREAD_POOL_NAME);
        scheduleTemplate.attach(THREAD_POOL_NAME, forkJoinPool);
        workName = "BloggerActiveFollower";
        dicGenerations = insDicGenerationDao.getByType(1);
        adult = insDicGenerationDao.getByType(2).get(1);
    }

    /**
     * 1.语言 2.国家 3.品牌 4.年龄、人种、性别
     * @param insBloggerMessage
     */
    @Override
    public void statistics(InsBloggerMessage insBloggerMessage){
        boolean sendMessage = false;
        long now = System.currentTimeMillis()/1000;
        long languageLimitTime = now - bloggerStatisticsAppConfig.getStLanguageIntervalHours() * 3600;
        long nationLimitTime = now - bloggerStatisticsAppConfig.getStNationIntervalHours() * 3600;
        long genderLimitTime = now - bloggerStatisticsAppConfig.getStGenderIntervalHours() * 3600;
//        long brandLimitTime = now - bloggerStatisticsAppConfig.getStBrandIntervalHours() * 3600;
        long incomeLimitTime = now - bloggerStatisticsAppConfig.getStIncomeIntervalHours() * 3600;
        val bloggerMain = bloggerMain(insBloggerMessage.getUid());

        if(bloggerMain == null){
            return;
        }

        // 语言
        if(InsBloggerMsgTypeCodeEnum.ST_LANGUAGE.getCode() == insBloggerMessage.getTypeCode()
                || (insBloggerMessage.getTypeCode() == InsBloggerMsgTypeCodeEnum.DEFAULT.getCode()
                && bloggerMain.getLastLanguageStTime() < languageLimitTime)){
            statisticsLanguage(insBloggerMessage.getUid(),bloggerMain);
            sendMessage = true;
        }

        // 国家
        if(InsBloggerMsgTypeCodeEnum.ST_NATION.getCode()== insBloggerMessage.getTypeCode()
                || (insBloggerMessage.getTypeCode() == InsBloggerMsgTypeCodeEnum.DEFAULT.getCode()
                && bloggerMain.getLastNationStTime() < nationLimitTime)){
            statisticsNation(insBloggerMessage.getUid(),bloggerMain);
            sendMessage = true;
        }

        // 暂时不统计品牌兴趣
//        if(InsBloggerMsgTypeCodeEnum.ST_BRAND.getCode() == insBloggerMessage.getTypeCode()
//                || (insBloggerMessage.getTypeCode() == InsBloggerMsgTypeCodeEnum.DEFAULT.getCode()
//                && bloggerMain.getLastBrandStTime() < brandLimitTime)){
//            // 关注品牌分类统计
//            statisticsFollowingCategoryRate(insBloggerMessage.getUid(),bloggerMain);
//            // 关注品牌统计
//            statisticsFollowing(insBloggerMessage.getUid());
//            sendMessage = true;
//        }

        if(InsBloggerMsgTypeCodeEnum.ST_GENERATION_RACE_GENDER.getCode() == insBloggerMessage.getTypeCode()
                || (insBloggerMessage.getTypeCode() == InsBloggerMsgTypeCodeEnum.DEFAULT.getCode()
                && bloggerMain.getLastGenderStTime() < genderLimitTime)){
            // AI分析成功样本数
            int sampleCount = insRelBloggerActiveFollowerDao.countByUidForAge(insBloggerMessage.getUid());

            if(sampleCount > 0){
                // 年龄
                statisticsAge(insBloggerMessage.getUid(), sampleCount);

                // 人种
                statisticsRace(insBloggerMessage.getUid(),sampleCount);
                bloggerMain.setLastRaceStTime(System.currentTimeMillis()/1000);

                // 成人
                double adultsRate = statisticsAdults(insBloggerMessage.getUid(),sampleCount);
                double femaleRate = statisticsFemale(insBloggerMessage.getUid(),sampleCount);
                InsStBloggerRealFollowing insStBloggerRealFollowing = insStBloggerRealFollowingDao.findByUid(insBloggerMessage.getUid());

                if(null == insStBloggerRealFollowing){
                    insStBloggerRealFollowing = new InsStBloggerRealFollowing();
                    insStBloggerRealFollowing.setUid(insBloggerMessage.getUid());
                    insStBloggerRealFollowing.setCreateTime(now);
                }
                insStBloggerRealFollowing.setAdultRate(adultsRate);
                insStBloggerRealFollowing.setGenderSampleCount(sampleCount);
                insStBloggerRealFollowing.setFemaleRate(femaleRate);
                insStBloggerRealFollowingDao.saveOrUpdate(insStBloggerRealFollowing);

                bloggerMain.setLastGenderStTime(now);
            }
            sendMessage = true;
        }

        // 统计收入信息
        if(InsBloggerMsgTypeCodeEnum.ST_INCOME.getCode() == insBloggerMessage.getTypeCode()
                || (insBloggerMessage.getTypeCode() == InsBloggerMsgTypeCodeEnum.DEFAULT.getCode()
                && bloggerMain.getLastIncomeStTime() < incomeLimitTime)){
            statisticsIncome(insBloggerMessage.getUid(),bloggerMain);
        }

        //大博主记录统计时间
        insBloggerMainDao.updateStActiveFollowerTime(bloggerMain);

        if(sendMessage){
            // 发送kafka
            InsBloggerMessage insBloggerMessageForEs = new InsBloggerMessage();
            insBloggerMessageForEs.setId(bloggerMain.getId());
            insBloggerMessageForEs.setUid(bloggerMain.getUid());
            insBloggerMsgBaseInfoProducer.send(bloggerStatisticsAppConfig.getInsMBloggerActiveFollowerDataToEsTopic(),insBloggerMessageForEs);
        }
    }

    /**
     * 年龄段
     * @param uid
     * @param sampleCount
     * @return
     */
    private void statisticsAge(long uid,int sampleCount){
        try{
            List<InsStBloggerGeneration> rates = new ArrayList<>(dicGenerations.size());

            for (int i = 0; i < dicGenerations.size(); i++) {
                long count = insRelBloggerActiveFollowerDao.countAgeRangeByUid(uid,dicGenerations.get(i).getGenerationStart(),dicGenerations.get(i).getGenerationEnd());
                if(count == 0){
                    continue;
                }
                long male = insRelBloggerActiveFollowerDao.countGenderByUid(uid,3,dicGenerations.get(i).getGenerationStart(),dicGenerations.get(i).getGenerationEnd());
                long female = insRelBloggerActiveFollowerDao.countGenderByUid(uid,2,dicGenerations.get(i).getGenerationStart(),dicGenerations.get(i).getGenerationEnd());
                InsStBloggerGeneration rate = new InsStBloggerGeneration();
                rate.setUid(uid);
                rate.setGeneration(dicGenerations.get(i).getGenerationName());
                rate.setGenerationRate(((int)((double)count/(double)sampleCount*1000)/1000.0));
                rate.setMaleRate(0.0);
                rate.setFemaleRate(0.0);
                rate.setCreateTime(System.currentTimeMillis()/1000);

                if(male >0){
                    rate.setMaleRate(((int)((double)male/(double)sampleCount*1000)/1000.0));
                }
                if(female >0){
                    rate.setFemaleRate(((int)((double)female/(double)sampleCount*1000)/1000.0));
                }
                rates.add(rate);
            }

            //排序
            Collections.sort(rates,(a,b)->{
                if(a.getGenerationRate() < b.getGenerationRate()){
                    return 1;
                }else if (a.getGenerationRate() > b.getGenerationRate()){
                    return -1;
                }
                return 0;
            });

            //排行
            for (int i = 0; i < rates.size(); i++) {
                rates.get(i).setGenerationRank(i+1);
            }

            insStBloggerGenerationDao.deleteByUid(uid);
            insStBloggerGenerationDao.saveBatch(rates);
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝年龄分布出错！",uid,e);
        }
    }

    /**
     * 成人占比
     * @param uid
     * @param sampleCount
     * @return
     */
    private double statisticsAdults(long uid,int sampleCount) {
        long count = insRelBloggerActiveFollowerDao.countAgeRangeByUid(uid, adult.getGenerationStart(),adult.getGenerationEnd());
        return ((int) ((double) count / (double) sampleCount * 1000)/1000.0);
    }



    /**
     * 女性占比
     * @param uid
     * @param sampleCount
     * @return
     */
    private double statisticsFemale(long uid,int sampleCount){
        long count = insRelBloggerActiveFollowerDao.countGenderByUid(uid,2,null,null);
        return ((int)((double)count/(double)sampleCount*1000)/1000.0);
    }

    /**
     * 人种占比
     * @param uid
     * @param sampleCount
     */
    private void statisticsRace(long uid, int sampleCount){
        try{
            val activeFollowerRace = insStBloggerRaceDao.getStByActiveFollower(uid);
            activeFollowerRace.removeIf(s-> StringUtils.isEmpty(s.getRace()));

            if(activeFollowerRace.size() < 1){
                return;
            }
            AtomicInteger rank= new AtomicInteger(1);
            activeFollowerRace.forEach(s ->{
                s.setUid(uid);
                s.setSampleCount(sampleCount);
                s.setRaceRate((int)(s.getRaceRate()/(double)sampleCount*1000)/1000.0);
                s.setRaceRank(rank.get());
                rank.getAndIncrement();
                s.setCreateTime(System.currentTimeMillis()/1000);
            });

            insStBloggerRaceDao.deleteByUid(uid);
            insStBloggerRaceDao.saveBatch(activeFollowerRace);
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝人种分布出错！",uid,e);
        }

    }

    /**
     * 语言占比
     * @param uid
     */
    private void statisticsLanguage(long uid,InsBloggerMain insBloggerMain){
        try{

            int sampleCount = insRelBloggerActiveFollowerDao.countByUidForLanguage(uid);

            if(sampleCount < 1){
                return;
            }

            val activeFollowerLanguage = insStBloggerLanguageDao.getStByActiveFollower(uid,bloggerStatisticsAppConfig.getStTop());
            activeFollowerLanguage.removeIf(s-> StringUtils.isEmpty(s.getLanguage()) || s.getLanguage().equals("un"));

            if(activeFollowerLanguage.size() < 1){
                return;
            }

            AtomicInteger rank= new AtomicInteger(1);
            activeFollowerLanguage.forEach(s ->{
                s.setUid(uid);
                s.setSampleCount(sampleCount);
                s.setLanguageRate((int)(s.getLanguageRate()/(double)sampleCount*1000)/1000.0);
                s.setLanguageRank(rank.get());
                rank.getAndIncrement();
                s.setCreateTime(System.currentTimeMillis()/1000);
            });
            insStBloggerLanguageDao.deleteByUid(uid);
            insStBloggerLanguageDao.saveBatch(activeFollowerLanguage);
            insBloggerMain.setLastLanguageStTime(System.currentTimeMillis() / 1000);
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝语言分布出错！",uid,e);
        }
    }

    /**
     * 国家占比
     * @param uid
     */
    private void statisticsNation(long uid,InsBloggerMain insBloggerMain){

        try{
            int sampleCount = insRelBloggerActiveFollowerDao.countByUidForNation(uid);

            if(sampleCount < 1){
                return;
            }
            val activeFollowerRegion = insStBloggerNationDao.getStByActiveFollower(uid,bloggerStatisticsAppConfig.getStTop());
            activeFollowerRegion.removeIf(s-> StringUtils.isEmpty(s.getNation()));

            if(activeFollowerRegion.size() < 1){
                return;
            }
            AtomicInteger rank= new AtomicInteger(1);
            activeFollowerRegion.forEach(s ->{
                s.setUid(uid);
                s.setSampleCount(sampleCount);
                s.setNationRate((int)(s.getNationRate()/(double)sampleCount*1000)/1000.0);
                s.setNationRank(rank.get());
                rank.getAndIncrement();
                s.setCreateTime(System.currentTimeMillis()/1000);
            });
            insStBloggerNationDao.deleteByUid(uid);
            insStBloggerNationDao.saveBatch(activeFollowerRegion);
            insBloggerMain.setLastNationStTime(System.currentTimeMillis() / 1000);
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝国家分布出错！",uid,e);
        }
    }

    /**
     * 统计活跃粉丝关注品牌博主的分类
     * @param uid
     */
    public void statisticsFollowingCategoryRate(long uid,InsBloggerMain insBloggerMain){
        try{
            long now = System.currentTimeMillis() / 1000;
            List<InsStBloggerFlBrandCategory> total = new ArrayList<>(bloggerStatisticsAppConfig.getStTop() * 2);
            // 获取关注品牌的分类
            List<InsStBloggerFlBrandCategory> insStBloggerFlBrandCategoryList =
                    insStBloggerFlBrandCategoryDao.findActiveFollowerBrandCategoryRateByUid(uid,bloggerStatisticsAppConfig.getStTop());
            // 获取关注全部的分类
            List<InsStBloggerFlBrandCategory> insStBloggerFlCategoryList =
                    insStBloggerFlBrandCategoryDao.findActiveFollowerCategoryRateByUid(uid,bloggerStatisticsAppConfig.getStTop());
            // 整合
            getCategoryList(uid,now,total,insStBloggerFlBrandCategoryList);
            getCategoryList(uid,now,total,insStBloggerFlCategoryList);
            // 保存新数据
            if(!total.isEmpty()){
                batchSaveFollowingCategory(uid,total);
            }
            insBloggerMain.setLastBrandStTime(now);
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝品牌分类出错！",uid,e);
        }
    }

    /**
     * 获取活跃粉丝关注品牌博主的分类
     * @param uid
     * @param now
     * @param total
     * @param insStBloggerFlBrandCategoryList
     */
    public void getCategoryList(long uid ,long now,List<InsStBloggerFlBrandCategory> total,
                                     List<InsStBloggerFlBrandCategory> insStBloggerFlBrandCategoryList){
        if(insStBloggerFlBrandCategoryList != null && !insStBloggerFlBrandCategoryList.isEmpty()){
            for(int i = 0; i < insStBloggerFlBrandCategoryList.size(); ++i){
                InsStBloggerFlBrandCategory insStBloggerFlBrandCategory = insStBloggerFlBrandCategoryList.get(i);
                insStBloggerFlBrandCategory.setCategoryRank(i + 1);
                insStBloggerFlBrandCategory.setCreateTime(now);
                insStBloggerFlBrandCategory.setUid(uid);
                total.add(insStBloggerFlBrandCategory);
            }
        }
    }

    /**
     * 保存 活跃粉丝关注品牌博主的分类
     * @param uid
     * @param total
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveFollowingCategory(long uid,List<InsStBloggerFlBrandCategory> total){
        insStBloggerFlBrandCategoryDao.deleteByUid(uid);
        insStBloggerFlBrandCategoryDao.saveBatch(total);
    }

    /**
     * 统计活跃粉丝关注品牌博主的分类
     * @param uid
     */
    public void statisticsFollowing(long uid){
        try{
            List<InsStBloggerFlBrand> insStBloggerFlBrandList = insStBloggerFlBrandDao.findActiveFollowerGroupByUid(uid,bloggerStatisticsAppConfig.getActiveFollowerBrandTop());

            if(insStBloggerFlBrandList == null || insStBloggerFlBrandList.isEmpty()){
                return;
            }

            for (int i = 0; i < insStBloggerFlBrandList.size(); i++) {
                insStBloggerFlBrandList.get(i).setUid(uid);
                insStBloggerFlBrandList.get(i).setCreateTime(System.currentTimeMillis()/1000);
                insStBloggerFlBrandList.get(i).setBrandRank(i+1);
            }

            batchSaveFollowingBrand(uid,insStBloggerFlBrandList);

        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝关注品牌出错！",uid,e);
        }
    }

    /**
     * 保存 活跃粉丝关注品牌博主的分类
     * @param uid
     * @param total
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveFollowingBrand(long uid,List<InsStBloggerFlBrand> total){
        insStBloggerFlBrandDao.deleteByUid(uid);
        insStBloggerFlBrandDao.saveBatch(total);
    }

    /**
     * 收入占比
     * @param uid
     */
    public void statisticsIncome(long uid,InsBloggerMain insBloggerMain){
        try{
            List<InsStBloggerIncome> insStBloggerIncomes = insStBloggerIncomeDao.findIncomeByUid(uid);
            if(insStBloggerIncomes != null && !insStBloggerIncomes.isEmpty()){
                int sampleCount = 0;
                for(InsStBloggerIncome insStBloggerIncome : insStBloggerIncomes){
                    if(insStBloggerIncome != null){
                        sampleCount += insStBloggerIncome.getIncomeRate();
                    }
                }
                if(sampleCount < 1){
                    return;
                }
                long now = System.currentTimeMillis() / 1000;
                InsStBloggerIncome insStBloggerIncome;
                for(int i = 0;i < insStBloggerIncomes.size();++i){
                    insStBloggerIncome = insStBloggerIncomes.get(i);
                    if(insStBloggerIncome != null){
                        insStBloggerIncome.setIncomeRank(i + 1);
                        insStBloggerIncome.setSampleCount(sampleCount);
                        insStBloggerIncome.setCreateTime(now);
                        insStBloggerIncome.setIncomeRate(insStBloggerIncome.getIncomeRate() / sampleCount);
                    }
                }
                // 批量保存
                batchSaveIncome(uid,insStBloggerIncomes);
                insBloggerMain.setLastIncomeStTime(now);
            }
        }catch (Exception e){
            log.error("统计uid为：{} 的博主活跃粉丝收入出错！",uid,e);
        }
    }

    /**
     * 批量保存收入统计
     * @param uid
     * @param insStBloggerIncomes
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchSaveIncome(long uid,List<InsStBloggerIncome> insStBloggerIncomes){
        insStBloggerIncomeDao.deleteByUid(uid);
        insStBloggerIncomeDao.saveBatch(insStBloggerIncomes);
    }
}
